Chapter 4 Kindergarten Readiness
Kindergarten readiness is an important indicator of whether children will succeed in the classroom. Based on data from KySTATS, JCPS students who entered school ready for kindergarten in 2016 were over three times as likely to achieve test results at or above their grade level on their standardized K-PREP math and reading tests in the 3rd grade. This is true for both JCPS students as a whole and Black JCPS students in particular.
Kentucky school districts evaluate kindergarten readiness using the BRIGANCE Early Childhood Kindergarten Screen III, which assesses child development across five areas:
- Academic/Cognitive Development
- Language Development
- Physical Development
- Self-help Skills
- Social and Emotional Skills
The BRIGANCE screener asks children to perform tasks such as identifying letters, numbers, and shapes or using a writing utensil. Parents provide information on their child’s self-help, social, and emotional skills such as whether their child can dress themselves, communicate their feelings, or take turns with other children. The results are a strong indicator of a student’s future academic performance.
It is important to note that the BRIGANCE screener has limitations. For example, children in professional care facilities are more likely to receive instruction tailored to the BRIGRANCE screener than children in a home setting with their parents or a relative. While many of the topics and questions represent important developmental foundations, child development includes factors beyond just the questions in BRIGANCE. It’s important to communicate the topics in BRIGRANCE to all families as well as ensure the questions in BRIGRANCE are not culturally biased.
You can see some of the questions included in BRIGANCE here:
- Example child assessment (academic, language, and physical measures)
- Example parent report (self-help, social, and emotional skills)
To view more data on kindergarten readiness, you can visit our Kindergarten Readiness page.
4.1 Overall Readiness
Since JCPS began tracking kindergarten readiness in 2012-13, overall readiness levels have fluctuated up to five percentage points per year but have remained largely unchanged. Other Kentucky students have seen their scores slightly increase.
load("early-childhood/raw_data/kready_ky.RData")
kready_ky %<>%
mutate(year = year - 1)
kready_total <- kready_ky %>%
filter(sex == "total",
race == "total",
frl_status == "total",
prior_setting == "All Students") %>%
filter(variable %in% c("lou", "mean")) %>%
mutate(District = if_else(variable == "lou", "JCPS", "Other Kentucky Districts"))
plt_by(kready_total,
District,
kready,
title_text = "Kindergarten Readiness",
caption_text = "Source: Greater Louisville Project
Data from the Kentucky Department of Education School Report Card",
school = T,
y_min = 40,
ymax = 60)
4.2 by Race
Racial disparities in kindergarten readiness have been largely persistent since the 2012-13 school year. The kindergarten readiness gap between Black students and white students shrank from 12 points in 2012-13 to around 5 points in 2016-17 before growing again. As of the 2018-19 school year, scores for the four groups included here are all within five points of their original levels.
kready_race <- kready_ky %>%
filter(variable == "lou",
sex == "total",
race %in% c("black", "white", "hispanic", "asian"),
frl_status == "total",
prior_setting == "All Students") %>%
mutate(Race = str_to_title(race))
plt_by(kready_race,
Race,
kready,
school = T,
title_text = "JCPS Kindergarten Readiness by Race",
caption_text = "Source: Greater Louisville Project
Data from the Kentucky Department of Education School Report Card")
4.3 by Prior Setting
The largest differences among kindergarten studnets are based on prior setting.
Children who were in licensed child care providers prior to entering school are most likely to be kindergarten ready, while children who stayed at home with a parent or guardian are least likely to be kindergarten ready.
Children who were previously enrolled in Head Start, a State-funded preschool program, or were in another home setting such as a private sitter or other family member (labeled “Other”), fall in the middle.
kready_louisville <- kready_ky %>%
filter(variable == "lou",
sex == "total",
race == "total",
frl_status == "total",
prior_setting %in% c("State Funded", "Head Start", "Child Care", "Home", "Other")) %>%
mutate(prior_setting = if_else(prior_setting == " State Funded", "State-Funded", prior_setting))
kready_louisville2 <- kready_ky %>%
filter(variable == "lou",
sex == "total",
race %in% c("black", "total"),
frl_status == "total",
prior_setting %in% c("State Funded", "Head Start", "Child Care", "Home", "Other")) %>%
mutate(prior_setting = if_else(prior_setting == " State Funded", "State-Funded", prior_setting))
plt_by(kready_louisville,
prior_setting,
kready,
school = T,
title_text = "JCPS Kindergarten Readiness by Prior Setting",
caption_text = "Source: Greater Louisville Project
Data from the Kentucky Department of Education School Report Card",
remove_legend_title = T)
4.3.1 Prior setting by Race
The graph below shows the prior setting of students entering JCPS kindergarten in 2019. About 60% of students were enrolled in a child care program or preschool outside the home, and around 40% of students were at home with their parents or another caretaker.
Students who are White, Asian, American Indian or Alaska Native, or of two or more races are more likely than average to be enrolled in professional care setting outside of the home before entering JCPS. Students who are Black are much less likely to be enrolled in professional child care, but much more likely to be enrolled in State Funded preschool. Hispanic students and students whose race is not known are much more likely to be in a home setting.
prior_setting_race <- readxl::read_excel("early-childhood/raw_data/ORR DRMS 9969 MetroUnitedWay.xlsx",
sheet = "Race", skip = 1)
prior_setting_race %<>%
pivot_longer(cols = `State Funded`:Other, names_to = "Prior Setting", values_to = "count") %>%
filter(!is.na(count)) %>%
group_by(Race) %>%
mutate(
percent = count / sum(count) * 100,
count = scales::comma(count, accuracy = 1)) %>%
ungroup() %>%
mutate(
Race = if_else(Race == "Grand Total", "All JCPS Students", Race),
Race = if_else(Race == "White (Non-Hispanic)", "White", Race),
Race = if_else(Race == "African American", "Black", Race),
Race = factor(Race, levels = rev(c("All Students",
"American Indian or Alaska Native",
"Asian",
"Black",
"Hispanic",
"White",
"Two or more races",
"Unknown")),
ordered = TRUE),
`Prior Setting` = factor(`Prior Setting`,
levels = rev(c("Child Care", "State Funded", "Head Start",
"Other", "Home")),
ordered = TRUE))
plot_ly(prior_setting_race, x = ~percent, y = ~Race,
color = ~`Prior Setting`,
colors = c("Child Care" = "#d63631",
"State Funded" = "#323844",
"Head Start" = "#eaab21",
"Other" = "#a7bfd7",
"Home" = "#7CE3B6"),
text = ~`count`,
type = 'bar',
hovertemplate = paste('Percent: %{x:.1f}%<br>Count: %{text}<extra></extra>')) %>%
layout(
title = "JCPS Prior Setting by Race",
font = list(family = "Montserrat"),
barmode = 'stack',
yaxis = list(title = ""),
xaxis = list(title = "Percent"),
legend = list(title = list(text = "Prior Setting")))4.3.2 Prior setting by Zip Code
Among children who enter JCPS, children in the Highlands and in Eastern Louisville are more likely than average to be enrolled in professional child care before entering JCPS. Children in West Louisville are most likely to be enrolled in State Funded preschool at JCPS, and children in South Louisville are most likely to be in a home setting.
prior_setting_zip <- readxl::read_excel("early-childhood/raw_data/ORR DRMS 9969 MetroUnitedWay.xlsx",
sheet = "Zip Code", skip=1)
prior_setting_zip %<>%
mutate(
zip = `Zip Code`,
total_students = `State Funded` + `Head Start` + `Child Care` + Home + Other) %>%
mutate(across(`State Funded`:`Other`, ~ . / total_students * 100)) %>%
filter(!is.na(zip))
prior_setting_map <- map_zip %>%
left_join(prior_setting_zip, by = "zip")
pal <- colorNumeric("viridis", domain = c(0, 75))
leaflet(prior_setting_map) %>%
addTiles() %>%
addPolygons(
color = "#444444", fillOpacity = 0.9, weight = 2, smoothFactor = 0.5,
fillColor = ~pal(`Child Care`), group = "Child Care") %>%
addPolygons(
color = "#444444", fillOpacity = 0.9, weight = 2, smoothFactor = 0.5,
fillColor = ~pal(`State Funded`), group = "State Funded") %>%
addPolygons(
color = "#444444", fillOpacity = 0.9, weight = 2, smoothFactor = 0.5,
fillColor = ~pal(`Head Start`), group = "Head Start") %>%
addPolygons(
color = "#444444", fillOpacity = 0.9, weight = 2, smoothFactor = 0.5,
fillColor = ~pal(`Home`), group = "Home") %>%
addPolygons(
color = "#444444", fillOpacity = 0.9, weight = 2, smoothFactor = 0.5,
fillColor = ~pal(`Other`), group = "Other") %>%
addLegend(pal = pal, values = c(0, 75), opacity = 0.7,
title = "Percent") %>%
addLayersControl(baseGroups = c("Child Care", "State Funded", "Head Start", "Home", "Other"),
options = layersControlOptions(collapsed = F))4.4 by Race and Prior setting
Combining the analysis by race and prior setting shows which settings are most effective at ensuring children enter kindergarten ready to learn. Click on the dropdown box on the right of the graph to toggle the prior setting.
Among the groups we examine here, the smallest racial disparities exist among children who were previously enrolled in Head Start or state-funded preschool. This is likely due to the fact that families must meet certain income limits to enroll their children in these programs, so children in these programs come from families with common economic situations. Black and Brown children in these settings enter kindergarten with relatively high readiness rates, and they have seen improvements since 2013-14.
Students in professional child care settings are the most kindergarten ready; however, racial disparities for these children are wider than for children in all other settings. As will be discussed later, this reflects differences in access to affordable and high-quality child care.
Differences in kindergarten readiness among children who were previously in a home setting with their parents (Home) or in another home-based setting (Other) are difficult to interpret because it reflects a wide variety of experiences for children. On average, children who were previously at home with their parents enter kindergarten the least ready to learn.
kready_race_plotly <- kready_ky %>%
filter(variable == "lou",
sex == "total",
race %in% c("black", "white", "hispanic", "asian"),
frl_status == "total",
prior_setting %in% c("All Students", "State Funded", "Head Start", "Child Care", "Home", "Other")) %>%
mutate(race = str_to_title(race)) %>%
pivot_wider(names_from = race, values_from = kready) %>%
mutate(year_label = paste0(year - 1, "-", year - 2000))
trnfm_list <-
list(
list(
type = 'filter',
target = ~prior_setting,
operation = 'in',
value = unique(kready_race_plotly$prior_setting)[1]))
plot_ly(kready_race_plotly, width = "100%") %>%
add_trace(x = ~year_label, y = ~Asian, name = "Asian", type = "scatter", mode = "lines",
line = list(color = '#a7bfd7', width = 2),
marker = list(color = '#a7bfd7', size = 6),
transforms = trnfm_list) %>%
add_trace(x = ~year_label, y = ~Black, name = "Black", type = "scatter", mode = "lines",
line = list(color = '#d63631', width = 2),
marker = list(color = '#d63631', size = 6),
transforms = trnfm_list) %>%
add_trace(x = ~year_label, y = ~Hispanic, name = "Hispanic", type = "scatter", mode = "lines",
line = list(color = '#eaab21', width = 2),
marker = list(color = '#eaab21', size = 6),
transforms = trnfm_list) %>%
add_trace(x = ~year_label, y = ~White, name = "White", type = "scatter", mode = "lines",
line = list(color = '#323844', width = 2),
marker = list(color = '#323844', size = 6),
transforms = trnfm_list) %>%
layout(title = "JCPS Kindergerten Readiness by Race",
font = list(family = "Montserrat"),
xaxis = list(title = "Year"),
yaxis = list(title = "Percent Ready", range = c(0, 100)),
hovermode = "x unified",
updatemenus = list(
list(
x = 1.25,
y = 0.75,
buttons = list(
list(method = "restyle",
args = list("transforms[0].value", unique(kready_race_plotly$prior_setting)[1]),
label = unique(kready_race_plotly$prior_setting)[1]),
list(method = "restyle",
args = list("transforms[0].value", unique(kready_race_plotly$prior_setting)[2]),
label = unique(kready_race_plotly$prior_setting)[2]),
list(method = "restyle",
args = list("transforms[0].value", unique(kready_race_plotly$prior_setting)[3]),
label = unique(kready_race_plotly$prior_setting)[3]),
list(method = "restyle",
args = list("transforms[0].value", unique(kready_race_plotly$prior_setting)[4]),
label = unique(kready_race_plotly$prior_setting)[4]),
list(method = "restyle",
args = list("transforms[0].value", unique(kready_race_plotly$prior_setting)[5]),
label = unique(kready_race_plotly$prior_setting)[5]),
list(method = "restyle",
args = list("transforms[0].value", unique(kready_race_plotly$prior_setting)[6]),
label = unique(kready_race_plotly$prior_setting)[6])))))4.5 by Geography
4.5.1 Student Zip Code
This data was acquired through a data request to JCPS. Note that this data only includes parents who send their children to JCPS, so does not include children who attend private school or who are homeschooled.
The data show wide disparities in kindergarten readiness across Louisville. Because some zip codes contain small numbers of students, we combine data over three years to increase the reliability of the data. Kindergarten readiness by zip code ranges from 30% in 40118 to 81% in 40205.
# Kready math
# ready w/ enrichments * (% distinguished + % proficient)
ready_prof_dist_math = (643 * (.317 + .353) + 2956 * (.122 + .355)) /
(643 * (1 - .143) + 2956 * (1 - .111)) * 100
not_ready_prof_dist_math = 3886 * (.034 + .160) / 3886 * (1 - .111) * 100
mult_math = ready_prof_dist_math / not_ready_prof_dist_math
# Kready reading
ready_prof_dist_reading = (643 * (.463 + .235) + 2956 * (.219 + .309)) /
(643 * (1 - .143) + 2956 * (1 - .111)) * 100
not_ready_prof_dist_reading = 3886 * (.057 + .165) / 3886 * (1 - .111) * 100
mult_reading = ready_prof_dist_reading / not_ready_prof_dist_reading
# black children
# ready w/ enrichments * (% distinguished + % proficient)
ready_prof_dist_math = (149 * (.148 + .376) + 940 * (.044 + .234)) /
(149 * (1 - .067) + 940 * (1 - .089)) * 100
not_ready_prof_dist_math = 1443 * (.013 + .089) / 1443 * (1 - .090) * 100
mult_math_black = ready_prof_dist_math / not_ready_prof_dist_math
# Kready reading
ready_prof_dist_reading = (149 * (.275 + .248) + 940 * (.091 + .240)) /
(149 * (1 - .067) + 940 * (1 - .089)) * 100
not_ready_prof_dist_reading = 1443 * (.019 + .106) / 1443 * (1 - .090) * 100
mult_reading_black = ready_prof_dist_reading / not_ready_prof_dist_reading
race_math = mult_math_black / mult_math
race_reading = mult_reading_black / mult_reading
# Ready in kready data
kready_zip <- readxl::read_excel("early-childhood/raw_data/Copy of 1920_Brigance Zip Code_Prior Settings TablesForORR.xlsx",
sheet = "ZipCode3Years",
range ="B4:K38",
col_names = c("zip", paste0(c("num_", "ready_", "notready_"),
rep(2018:2020, each = 3))),
col_types = c("text", rep("numeric", 9)),
na = "*")
# Clean and organize data frame
kready_zip %<>%
pivot_longer(num_2018:notready_2020, names_to = c("var_type", "year"), names_sep = "_") %>%
filter(var_type != "notready") %>%
mutate(
var_type = case_when(var_type == "num" ~ "population",
var_type == "ready" ~ "percent")) %>%
transmute(
zip, year, var_type,
kready = if_else(var_type == "percent", value * 100, value))
# Summarize data frame over three years due to unstable data
kready_zip_sum <- kready_zip %>%
pivot_wider(names_from = var_type, values_from = kready) %>%
group_by(zip) %>%
filter(all(!is.na(percent))) %>%
summarise(
percent = weighted.mean(percent, population),
population = sum(population),
.groups = "drop") %>%
rename(kready = percent)
# Join data to map
map_zip %<>% left_join(kready_zip_sum, by = "zip")
ggplot(map_zip) +
geom_sf(aes(fill = kready), color = "white") +
#scale_fill_manual(values = viridis::viridis(6, direction = -1), na.value = "grey") +
viridis::scale_fill_viridis(na.value = "grey",
name = "Percent Ready") +
theme_bw(base_size = 22, base_family = "Montserrat") +
theme(panel.grid = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
panel.border = element_blank()) +
labs(title = "JCPS Kindergarden Readiness by Student's Home Zip Code",
subtitle = "Average for the school years 2017-2018, 2018-2019, and 2019-2020",
caption_text = "Source: Greater Louisville Project
Data from JCPS") +
theme(plot.caption = element_text(lineheight = .5)) +
theme(
panel.background = element_rect(fill = "transparent", color = NA), # bg of the panel
plot.background = element_rect(fill = "transparent", color = NA), # bg of the plot
legend.background = element_rect(fill = "transparent", color = "transparent"), # get rid of legend bg
legend.box.background = element_rect(fill = "transparent", color = "transparent"), # get rid of legend panel bg
legend.key = element_rect(fill = "transparent",colour = NA))
4.5.2 School Location
4.5.2.1 Elementary School Assignment Area
This map shows kindergarten readiness results by school. The areas on the map represent student assignment areas for individual schools, and the thicker white lines show student assignment clusters.
load("early-childhood/raw_data/kready_jc.RData")
load("early-childhood/raw_data/map_elementary.RData")
# Filter out
kready_jc_subset <- kready_jc %>%
filter(code != "275",
year == 2020,
demographic == "All Students",
prior_setting == "All Students") %>%
mutate(code = str_sub(code, 4, 6) %>%
as.numeric)
map_elementary %<>%
rename(
SCHOOL_NAME = SCHOOL_NAM,
LOCATION = LocNumber,
CLUSTER = ClusterNum)
map_elementary %<>%
left_join(kready_jc_subset, by = c("LOCATION" = "code"))
map_cluster <- map_elementary %>%
group_by(CLUSTER) %>%
summarise(
kready = weighted.mean(kready, num_students),
.groups = "drop")
ggplot(map_elementary) +
geom_sf(aes(fill = kready), color = "white") +
#scale_fill_manual(values = viridis::viridis(6, direction = -1), na.value = "grey") +
viridis::scale_fill_viridis(na.value = "grey",
name = "Percent Ready") +
theme_bw(base_size = 22, base_family = "Montserrat") +
theme(panel.grid = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
panel.border = element_blank()) +
labs(title = "JCPS Kindergarden Readiness by School Location, 2019-2020",
caption_text = "Source: Greater Louisville Project
Data from the Kentucky Department of Education School Report Card") +
theme(plot.caption = element_text(lineheight = .5)) +
theme(
panel.background = element_rect(fill = "transparent", color = NA), # bg of the panel
plot.background = element_rect(fill = "transparent", color = NA), # bg of the plot
legend.background = element_rect(fill = "transparent", color = "transparent"), # get rid of legend bg
legend.box.background = element_rect(fill = "transparent", color = "transparent"), # get rid of legend panel bg
legend.key = element_rect(fill = "transparent",colour = NA)) +
geom_sf(data = map_cluster, fill=NA, color = "white", size = 1)
4.5.2.2 Elementary School Cluster
This map shows kindergarten readiness results by elementary school clusters.
ggplot(map_cluster) +
geom_sf(aes(fill = kready), color = "white", size = 1) +
#scale_fill_manual(values = viridis::viridis(6, direction = -1), na.value = "grey") +
viridis::scale_fill_viridis(na.value = "grey",
name = "Percent Ready") +
theme_bw(base_size = 22, base_family = "Montserrat") +
theme(panel.grid = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
panel.border = element_blank()) +
labs(title = "JCPS Kindergarden Readiness by School Cluster, 2019-2020",
caption_text = "Source: Greater Louisville Project
Data from the Kentucky Department of Education School Report Card") +
theme(plot.caption = element_text(lineheight = .5)) +
theme(
panel.background = element_rect(fill = "transparent", color = NA), # bg of the panel
plot.background = element_rect(fill = "transparent", color = NA), # bg of the plot
legend.background = element_rect(fill = "transparent", color = "transparent"), # get rid of legend bg
legend.box.background = element_rect(fill = "transparent", color = "transparent"), # get rid of legend panel bg
legend.key = element_rect(fill = "transparent",colour = NA))